﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

namespace CommonUtil
{
    /// <summary>
    /// 方法类型（静态，动态，有无入参）
    /// </summary>
    public enum MethodType
    {
        /// <summary>
        /// 实例化对象方法，无入参
        /// </summary>
        InstanceNull,
        /// <summary>
        /// 实例化对象方法，带入参
        /// </summary>
        InstanceParams,
        /// <summary>
        /// 静态类方法，无入参
        /// </summary>
        StaticNull,
        /// <summary>
        /// 静态类方法，带入参
        /// </summary>
        StaticParams
    }

    /// <summary>
    /// 反射辅助类
    /// </summary>
    public class ReflectionUtil
    {
        Assembly assembly = null;
        object classObj = null;
        /// <summary>
        /// 
        /// </summary>
        public object ClassObj
        {
            get { return classObj; }
            set { classObj = value; }
        }
        Type classType = null;
        /// <summary>
        /// 
        /// </summary>
        public Type ClassType
        {
            get { return classType; }
            set { classType = value; }
        }        

        /// <summary>
        /// 初始化反射辅助类
        /// </summary>
        /// <param name="nameSpace"></param>
        /// <param name="className"></param>
        public ReflectionUtil(string nameSpace, string className)
        {
            if (string.IsNullOrEmpty(nameSpace) || string.IsNullOrEmpty(className))
            {
                return;
            }
            try
            {
                this.assembly = Assembly.Load(nameSpace);
                string fulClsName = nameSpace + "." + className;
                this.classObj = assembly.CreateInstance(fulClsName);
                this.classType = classObj.GetType();
            }
            catch(Exception)
            {
            }
        }

        #region 获取和设置类属性
        public object GetProperty(string propertyName)
        {
            if (string.IsNullOrEmpty(propertyName)) return null;
            try
            {
                PropertyInfo propInfo = classType.GetProperty(propertyName);
                return propInfo.GetValue(classObj, null);
            }
            catch (Exception)
            {
                return null;
            }
        }
        public void SetPropertys(string[] propertyNameArray, string[] propertyValueArray)
        {
            if (propertyNameArray.Length == propertyValueArray.Length)
            {
                for (int i = 0, j = propertyNameArray.Length; i < j; i++)
                {
                    SetProperty(propertyNameArray[i], propertyValueArray[i]);
                }
            }
        }
        public void SetProperty(string propertyName, string propertyValue)
        {
            PropertyInfo propertyInfo = classType.GetProperty(propertyName);

            if (IsType(propertyInfo.PropertyType, "System.String"))
            {
                propertyInfo.SetValue(classObj, propertyValue, null);
                return;
            }
            if (IsType(propertyInfo.PropertyType, "System.Boolean"))
            {
                propertyInfo.SetValue(classObj, Boolean.Parse(propertyValue), null);
                return;
            }
            if (IsType(propertyInfo.PropertyType, "System.Int32"))
            {
                if (propertyValue != "")
                    propertyInfo.SetValue(classObj, int.Parse(propertyValue), null);
                else
                    propertyInfo.SetValue(classObj, 0, null);
                return;
            }
            if (IsType(propertyInfo.PropertyType, "System.Decimal"))
            {
                if (propertyValue != "")
                    propertyInfo.SetValue(classObj, Decimal.Parse(propertyValue), null);
                else
                    propertyInfo.SetValue(classObj, new Decimal(0), null);
                return;
            }
            if (IsType(propertyInfo.PropertyType, "System.Nullable`1[System.DateTime]"))
            {
                if (propertyValue != "")
                {
                    try
                    {
                        propertyInfo.SetValue(classObj, (DateTime?)DateTime.ParseExact(propertyValue, "yyyy-MM-dd HH:mm:ss", null), null);
                    }
                    catch
                    {
                        propertyInfo.SetValue(classObj, (DateTime?)DateTime.ParseExact(propertyValue, "yyyy-MM-dd", null), null);
                    }
                }
                else
                    propertyInfo.SetValue(classObj, null, null);
                return;
            }
        }
        /// <summary>
        /// 类型匹配（用于设置类属性SetProperty）
        /// </summary>
        /// <param name="type"></param>
        /// <param name="typeName"></param>
        /// <returns></returns>
        public bool IsType(Type type, string typeName)
        {
            //bool isType = false;
            if (type.ToString() == typeName)
                return true;
            if (type.ToString() == "System.Object")
                return false;
            return IsType(type.BaseType, typeName);
        }
        #endregion 获取和设置类属性

        #region 调用类的Public实例方法
        /// <summary>
        /// 调用类方法，有返回值
        /// </summary>
        /// <param name="methodName">方法名</param>
        /// <param name="methodType">方法类型</param>
        /// <param name="paramsListString">参数字符串</param>
        /// <param name="splitChar">参数分隔符</param>
        /// <returns></returns>
        public object CallMethodReturn(string methodName, MethodType methodType, string paramsListString, string splitChar)
        {
            object result = null;
            if (string.IsNullOrEmpty(methodName)) return result;
            try
            {
                //MethodType mt = (MethodType)Enum.Parse(typeof(MethodType), methodType, true);
                MethodInfo mi = classType.GetMethod(methodName);
                object[] parameters = null;

                if (!string.IsNullOrEmpty(paramsListString))
                {
                    parameters = paramsListString.Split(Convert.ToChar(splitChar));
                }
                result = CallMethod(mi, methodType, parameters);                
            }
            catch (Exception)
            {
                result = null;
            }
            return result;
        }
        /// <summary>
        /// 调用类方法，无返回值
        /// </summary>
        /// <param name="methodName"></param>
        /// <param name="methodType"></param>
        /// <param name="paramsListString"></param>
        /// <param name="splitChar"></param>
        public void CallMethodVoid(string methodName, MethodType methodType, string paramsListString, string splitChar)
        {
            if (string.IsNullOrEmpty(methodName)) return;
            CallMethodReturn(methodName, methodType, paramsListString, splitChar);
        }

        public object CallMethodArgs(string methodName, MethodType methodType, Args args)
        {
            object result = null;
            if (string.IsNullOrEmpty(methodName)) return result;
            try
            {
                MethodInfo mi = classType.GetMethod(methodName);

                if (args !=null)
                {
                    result = CallMethod(mi, methodType, new object [] { args });
                }
            }
            catch (Exception)
            {
                result = null;
            }
            return result;
        }

        /// <summary>
        /// 真正的调用方法，私有
        /// </summary>
        /// <param name="mi"></param>
        /// <param name="mt"></param>
        /// <param name="parameters"></param>
        /// <returns></returns>
        private object CallMethod(MethodInfo mi, MethodType mt, object[] parameters)
        {
            object result = null;
            try
            {
                switch (mt)
                {
                    case MethodType.InstanceNull:
                        result = mi.Invoke(classObj, null);
                        break;
                    case MethodType.InstanceParams:
                        result = mi.Invoke(classObj, parameters);
                        break;
                    case MethodType.StaticNull:
                        result = mi.Invoke(null, null);
                        break;
                    case MethodType.StaticParams:
                        result = mi.Invoke(null, parameters);
                        break;
                    default:
                        break;
                }
            }
            catch (Exception)
            {
                result = null;
            }
            return result;
        }
        #endregion 

    }
}
